#include <linux/kernel.h>
#include <linux/gpio.h>
#include <linux/of_gpio.h>
#include <linux/module.h>
#include <linux/of_device.h>
#include <linux/slab.h>
#include <linux/delay.h>

/*

测试节点； 
echo 0 > /sys/devices/platform/io_control/relay_control
echo 1 > /sys/devices/platform/io_control/green_control

设备树配置： 
 rk3568-evb1-ddr4-v10.dts
 \kernel\arch\arm64\boot\dts\rockchip\rk3568-evb.dtsi
 io_control {
		compatible  = "goingup,io-control";
		status = "okay";

		wifi_power = <&gpio0 RK_PC1 GPIO_ACTIVE_LOW>;
		spk_power = <&gpio3 RK_PB4 GPIO_ACTIVE_HIGH>;
		working_led = <&gpio0 RK_PB7 GPIO_ACTIVE_HIGH>;
		pwm_led1 = <&gpio3 RK_PC2 GPIO_ACTIVE_HIGH>;
		pwm_led2 = <&gpio3 RK_PA1 GPIO_ACTIVE_LOW>;
		doorbell = <&gpio2 RK_PD3 GPIO_ACTIVE_HIGH>;
		open_door = <&gpio2 RK_PD1 GPIO_ACTIVE_HIGH>;
		fire_alm = <&gpio2 RK_PD0 GPIO_ACTIVE_HIGH>;
		ds = <&gpio2 RK_PD2 GPIO_ACTIVE_HIGH>;
		green_led = <&gpio4 RK_PC2 GPIO_ACTIVE_HIGH>;
		red_led = <&gpio4 RK_PC3 GPIO_ACTIVE_HIGH>;
		relay_en = <&gpio3 RK_PA0 GPIO_ACTIVE_HIGH>;
	};

    驱动：  drivers\gpiogpio\io-control.c
*/

#define OUTPUT_HIGH 1
#define OUTPUT_LOW  0

#define DEBUG_FLAG 1

#ifdef DEBUG_FLAG
	#define DBG_IO(fmt,arg...)   printk("<<-IO-DEBUG->> "fmt"\n",##arg)
#else
	#define DBG_IO(fmt,arg...)	NULL 
#endif

unsigned int usb_host0; 
unsigned int wifi_power;
unsigned int spk_power;
unsigned int working_led;
unsigned int led_power;
unsigned int pwm_led1;
unsigned int pwm_led2;
unsigned int doorbell;
unsigned int open_door;
unsigned int fire_alm;
unsigned int ds;
unsigned int green_led;
//sys/devices/platform/io_control/red_control
// 思考一个问题？ 
// 为什么会在 sys/devices/platform/io_control/red_control 下创建节点
// rk3568-evb.dtsi  
// 	io_control {} 
unsigned int red_led;
unsigned int relay_en;
unsigned int r485_en;
unsigned int r485_rx;
unsigned int r485_tx;
unsigned int n4g_en;
unsigned int bl_en;
unsigned int usb_en;

static ssize_t read_io_status(struct device *dev, struct device_attribute *attr, char *buf)
{
	int  host0, value;
	
	host0 = gpio_get_value(usb_host0);
	

	value = host0 & 0xf;
	//rgb = ((rvalue & 0xf) << 8) + ((gvalue & 0xf) << 4) + (bvalue & 0xf);
 
	DBG_IO("host0:0x%x, value=0x%x\n", host0, value);

	return snprintf(buf,PAGE_SIZE,"0x%x\n", value);
}
static ssize_t gpio_ledpower_show (struct device *dev,
			struct device_attribute *attr, char *buf)
{
	return sprintf(buf, "%d\n", gpio_get_value(led_power)); //获取GPIO的电平，1为高电平，0为低电平
}
static ssize_t gpio_ledpower_store(struct device *dev, struct device_attribute *attr,
						const char *buf, size_t size)
{
	int val;
	int ret;

	ret = kstrtoint(buf, 10, &val); //输入一个字符然后转换成10进制整形数

        if (ret) {
		printk("%s: kstrtoint error return %d\n", __func__, ret);
		return -1;
        }

	if (val== 1) { //如果echo 1 到节点则调用

		printk("-hl-: _%s_ :gpio pull up\n", __func__);
		gpio_direction_output(led_power, val); //设置GPIO电平为高电平

	} else if (val == 0) { //如果echo 0 到节点则调用

		printk("-hl-: _%s_ :gpio pull down\n", __func__);
		gpio_direction_output(led_power, val); //设置GPIO电平为低电平

	} else {

		printk("I only support 0 or 1 to ctrl led power\n");

	}
	return size;
	//return -1;
}

static ssize_t gpio_r485en_show (struct device *dev,
			struct device_attribute *attr, char *buf)
{
	return sprintf(buf, "%d\n", gpio_get_value(r485_en)); //获取GPIO的电平，1为高电平，0为低电平
}
static ssize_t gpio_r485en_store(struct device *dev, struct device_attribute *attr,
						const char *buf, size_t size)
{
	int val;
	int ret;

	ret = kstrtoint(buf, 10, &val); //输入一个字符然后转换成10进制整形数

        if (ret) {
		printk("%s: kstrtoint error return %d\n", __func__, ret);
		return -1;
        }

	if (val== 1) { //如果echo 1 到节点则调用

		printk("-hl-: _%s_ :gpio pull up\n", __func__);
		gpio_direction_output(r485_en, val); //设置GPIO电平为高电平

	} else if (val == 0) { //如果echo 0 到节点则调用

		printk("-hl-: _%s_ :gpio pull down\n", __func__);
		gpio_direction_output(r485_en, val); //设置GPIO电平为低电平

	} else {

		printk("I only support 0 or 1 to ctrl r485en\n");

	}
	return size;
	//return -1;
}


static ssize_t gpio_n4gen_show (struct device *dev,
			struct device_attribute *attr, char *buf)
{
	return sprintf(buf, "%d\n", gpio_get_value(n4g_en)); //获取GPIO的电平，1为高电平，0为低电平
}
static ssize_t gpio_n4gen_store(struct device *dev, struct device_attribute *attr,
						const char *buf, size_t size)
{
	int val;
	int ret;

	ret = kstrtoint(buf, 10, &val); //输入一个字符然后转换成10进制整形数

        if (ret) {
		printk("%s: kstrtoint error return %d\n", __func__, ret);
		return -1;
        }

	if (val== 1) { //如果echo 1 到节点则调用

		printk("-hl-: _%s_ :gpio pull up\n", __func__);
		gpio_direction_output(n4g_en, val); //设置GPIO电平为高电平

	} else if (val == 0) { //如果echo 0 到节点则调用

		printk("-hl-: _%s_ :gpio pull down\n", __func__);
		gpio_direction_output(n4g_en, val); //设置GPIO电平为低电平

	} else {

		printk("I only support 0 or 1 to ctrl r485en\n");

	}
	return size;
	//return -1;
}

static ssize_t gpio_blen_show (struct device *dev,
			struct device_attribute *attr, char *buf)
{
	return sprintf(buf, "%d\n", gpio_get_value(bl_en)); //获取GPIO的电平，1为高电平，0为低电平
}
static ssize_t gpio_blen_store(struct device *dev, struct device_attribute *attr,
						const char *buf, size_t size)
{
	int val;
	int ret;

	ret = kstrtoint(buf, 10, &val); //输入一个字符然后转换成10进制整形数

        if (ret) {
		printk("%s: kstrtoint error return %d\n", __func__, ret);
		return -1;
        }

	if (val== 1) { //如果echo 1 到节点则调用

		printk("-hl-: _%s_ :gpio pull up\n", __func__);
		gpio_direction_output(bl_en, val); //设置GPIO电平为高电平

	} else if (val == 0) { //如果echo 0 到节点则调用

		printk("-hl-: _%s_ :gpio pull down\n", __func__);
		gpio_direction_output(bl_en, val); //设置GPIO电平为低电平

	} else {

		printk("I only support 0 or 1 to ctrl blen\n");

	}
	return size;
	//return -1;
}


static ssize_t gpio_usben_show (struct device *dev,
			struct device_attribute *attr, char *buf)
{
	return sprintf(buf, "%d\n", gpio_get_value(usb_en)); //获取GPIO的电平，1为高电平，0为低电平
}
static ssize_t gpio_usben_store(struct device *dev, struct device_attribute *attr,
						const char *buf, size_t size)
{
	/*int val;
	int ret;

	ret = kstrtoint(buf, 10, &val); //输入一个字符然后转换成10进制整形数

        if (ret) {
		printk("%s: kstrtoint error return %d\n", __func__, ret);
		return -1;
        }

	if (val== 1) { //如果echo 1 到节点则调用

		printk("-hl-: _%s_ :gpio pull up\n", __func__);
		gpio_direction_output(n4g_en, val); //设置GPIO电平为高电平

	} else if (val == 0) { //如果echo 0 到节点则调用

		printk("-hl-: _%s_ :gpio pull down\n", __func__);
		gpio_direction_output(n4g_en, val); //设置GPIO电平为低电平

	} else {

		printk("I only support 0 or 1 to ctrl r485en\n");

	}
	return size;*/
	return -1;
}

static ssize_t gpio_doorbell_show (struct device *dev,
			struct device_attribute *attr, char *buf)
{
	return sprintf(buf, "%d\n", gpio_get_value(doorbell)); //获取GPIO的电平，1为高电平，0为低电平
}
static ssize_t gpio_opendoor_show (struct device *dev,
			struct device_attribute *attr, char *buf)
{
	return sprintf(buf, "%d\n", gpio_get_value(open_door)); //获取GPIO的电平，1为高电平，0为低电平
}
static ssize_t gpio_firealm_show (struct device *dev,
			struct device_attribute *attr, char *buf)
{
	return sprintf(buf, "%d\n", gpio_get_value(fire_alm)); //获取GPIO的电平，1为高电平，0为低电平
}
static ssize_t gpio_ds_show (struct device *dev,
			struct device_attribute *attr, char *buf)
{
	return sprintf(buf, "%d\n", gpio_get_value(ds)); //获取GPIO的电平，1为高电平，0为低电平
}
static ssize_t write_io_status(struct device *dev, struct device_attribute *attr, const char *buf,size_t count)
{	
	char cmd;

	sscanf(buf, "%c", &cmd);
	DBG_IO("%c\n", cmd);
	//if((cmd == 'r') || (cmd == 'R'))
	//	gpio_set_value(usb_host0, 1);
		
    return count;
}

static ssize_t write_pwm1_status(struct device *dev, struct device_attribute *attr, const char *buf,size_t count)
{	
	char cmd;

	sscanf(buf, "%c", &cmd);
	DBG_IO("%c\n", cmd);
	
	if(cmd == '0')
	{
		gpio_set_value(pwm_led1, 0);
	}
	else if(cmd == '1')
	{
		gpio_set_value(pwm_led1, 1);
	}
		
    return count;
}

static ssize_t write_pwm2_status(struct device *dev, struct device_attribute *attr, const char *buf,size_t count)
{	
	char cmd;

	sscanf(buf, "%c", &cmd);
	DBG_IO("%c\n", cmd);
	
	if(cmd == '0')
	{
		gpio_set_value(pwm_led2, 0);
	}
	else if(cmd == '1')
	{
		gpio_set_value(pwm_led2, 1);
	}
		
    return count;
}

static ssize_t write_doorbell_status(struct device *dev, struct device_attribute *attr, const char *buf,size_t count)
{	
	char cmd;

	sscanf(buf, "%c", &cmd);
	DBG_IO("%c\n", cmd);
	
	if(cmd == '0')
	{
		gpio_set_value(doorbell, 0);
	}
	else if(cmd == '1')
	{
		gpio_set_value(doorbell, 1);
	}
		
    return count;
	//return -1;
}

static ssize_t write_open_door_status(struct device *dev, struct device_attribute *attr, const char *buf,size_t count)
{	
	/*char cmd;

	sscanf(buf, "%c", &cmd);
	DBG_IO("%c\n", cmd);
	
	if(cmd == '0')
	{
		gpio_set_value(open_door, 0);
	}
	else if(cmd == '1')
	{
		gpio_set_value(open_door, 1);
	}
		
    return count;*/
	return -1;
}

static ssize_t write_fire_alm_status(struct device *dev, struct device_attribute *attr, const char *buf,size_t count)
{	
	/*char cmd;

	sscanf(buf, "%c", &cmd);
	DBG_IO("%c\n", cmd);
	
	if(cmd == '0')
	{
		gpio_set_value(fire_alm, 0);
	}
	else if(cmd == '1')
	{
		gpio_set_value(fire_alm, 1);
	}
		
    return count;*/
	return -1;
}

static ssize_t write_ds_status(struct device *dev, struct device_attribute *attr, const char *buf,size_t count)
{	
	/*char cmd;

	sscanf(buf, "%c", &cmd);
	DBG_IO("%c\n", cmd);
	
	if(cmd == '0')
	{
		gpio_set_value(ds, 0);
	}
	else if(cmd == '1')
	{
		gpio_set_value(ds, 1);
	}
		
    return count;*/
	return -1;
}

static ssize_t write_green_status(struct device *dev, struct device_attribute *attr, const char *buf,size_t count)
{	
	char cmd;

	sscanf(buf, "%c", &cmd);
	DBG_IO("%c\n", cmd);
	
	if(cmd == '0')
	{
		gpio_set_value(green_led, 0);
	}
	else if(cmd == '1')
	{
		gpio_set_value(green_led, 1);
	}
		
    return count;
}

static ssize_t write_red_status(struct device *dev, struct device_attribute *attr, const char *buf,size_t count)
{	
	char cmd;

	sscanf(buf, "%c", &cmd);
	DBG_IO("%c\n", cmd);
	
	if(cmd == '0')
	{
		gpio_set_value(red_led, 0);
	}
	else if(cmd == '1')
	{
		gpio_set_value(red_led, 1);
	}
		
    return count;
}


static ssize_t write_relay_status(struct device *dev, struct device_attribute *attr, const char *buf,size_t count)
{	
	char cmd;

	sscanf(buf, "%c", &cmd);
	DBG_IO("%c\n", cmd);
	
	if(cmd == '0')
	{
		gpio_set_value(relay_en, 0);
	}
	else if(cmd == '1')
	{
		gpio_set_value(relay_en, 1);
	}
		
    return count;
}
// red_control 就是节点名称 
// /sys/devices/platform/io_control/pwm2_control
static struct device_attribute io_control_attrs[] = {
	__ATTR(io_control, 0664, read_io_status, write_io_status),
	__ATTR(ledpower_control, 0664, gpio_ledpower_show, gpio_ledpower_store),
	__ATTR(pwm1_control, 0664, read_io_status, write_pwm1_status),
	__ATTR(pwm2_control, 0664, read_io_status, write_pwm2_status),
	__ATTR(doorbell_control, 0664, gpio_doorbell_show, write_doorbell_status),
	__ATTR(open_door_control, 0664, gpio_opendoor_show, write_open_door_status),
	__ATTR(fire_alm_control, 0664, gpio_firealm_show, write_fire_alm_status),
	__ATTR(ds_control, 0664, gpio_ds_show, write_ds_status),
	__ATTR(green_control, 0664, read_io_status, write_green_status),
	__ATTR(red_control, 0664, read_io_status, write_red_status),
	__ATTR(relay_control, 0664, read_io_status, write_relay_status),
	__ATTR(r485en_control, 0664, gpio_r485en_show, gpio_r485en_store),
	__ATTR(n4gen_control, 0664, gpio_n4gen_show, gpio_n4gen_store),
	__ATTR(blen_control, 0664, gpio_blen_show, gpio_blen_store),
	__ATTR(usben_control, 0664, gpio_usben_show, gpio_usben_store),
};

static int io_control_probe(struct platform_device *pdev)
{
	int ret = 0;  
	int err;
	int i;
	enum of_gpio_flags io_control_flags;
	struct device_node *of_node = pdev->dev.of_node;	
	
	DBG_IO("%s,start____ \n",__func__);
/*	
gpio_pin  = of_get_named_gpio_flags(np, "irq-gpio, 0,&io_control_flags);

	if (!gpio_is_valid(gpio_pin)) {
			dev_err(&pdev->dev, "invalid gpio%d\n", gpio_pin);
			//goto out;
		} 

	gpio_request(gpio_pin, 1);
	client->irq = gpio_to_irq(gpio_pin);
ret = request_irq(client->irq, inv_irq_handler, irq_flags | IRQF_SHARED,"inv_irq", st);*/


/*	read_wiegand_d0 = of_get_named_gpio_flags(of_node, "read_wiegand_d0", 0, &io_control_flags);
	if (gpio_is_valid(read_wiegand_d0)){
				//gpio_direction_output(read_wiegand_d0, 0);//设置成输出低电平
				gpio_direction_output(read_wiegand_d0, 1);//设置成输出高电平
	}
	if (gpio_is_valid(read_wiegand_d0)){
		irq = gpio_to_irq(read_wiegand_d0);//返回值是中断号
		ret = request_threaded_irq(irq, NULL,gtp_irq_handler,
				irq_flags | IRQF_ONESHOT,name,ts);//申请中断
		
	}*/
//	gpio_request(read_wiegand_d0, 1);
//	irq = gpio_to_irq(read_wiegand_d0);



////////////////////////////////////////////////////////////////////////////////////////////////	
	r485_rx = of_get_named_gpio_flags(of_node, "r485_rx", 0, &io_control_flags);
	
	if (!gpio_is_valid(r485_rx)) {
		dev_err(&pdev->dev, "invalid gpio%d\n", r485_rx);
		//goto out;
	} else {
		err  = devm_gpio_request(&pdev->dev, r485_rx, "r485_rx");
		if (err) {
			dev_err(&pdev->dev,
				"failed to request GPIO%d for usb host0\n", r485_rx);
			ret = err;
			goto out;
		}
		gpio_direction_output(r485_rx, OUTPUT_HIGH);
		DBG_IO("xxxx r485_rx:%d\n", gpio_get_value(r485_rx));
	}	
	r485_tx = of_get_named_gpio_flags(of_node, "r485_tx", 0, &io_control_flags);
	
	if (!gpio_is_valid(r485_tx)) {
		dev_err(&pdev->dev, "invalid gpio%d\n", r485_tx);
		//goto out;
	} else {
		err  = devm_gpio_request(&pdev->dev, r485_tx, "r485_tx");
		if (err) {
			dev_err(&pdev->dev,
				"failed to request GPIO%d for usb host0\n", r485_tx);
			ret = err;
			goto out;
		}
		gpio_direction_output(r485_tx, OUTPUT_HIGH);
		DBG_IO("xxxx r485_tx:%d\n", gpio_get_value(r485_tx));
	}	

	wifi_power = of_get_named_gpio_flags(of_node, "wifi_power", 0, &io_control_flags);
	
	if (!gpio_is_valid(wifi_power)) {
		dev_err(&pdev->dev, "invalid gpio%d\n", wifi_power);
		//goto out;
	} else {
		err  = devm_gpio_request(&pdev->dev, wifi_power, "wifi_power");
		if (err) {
			dev_err(&pdev->dev,
				"failed to request GPIO%d for usb host0\n", wifi_power);
			ret = err;
			goto out;
		}
		gpio_direction_output(wifi_power, OUTPUT_LOW);
		DBG_IO("xxxx wifi_power:%d\n", gpio_get_value(wifi_power));
	}	

	spk_power = of_get_named_gpio_flags(of_node, "spk_power", 0, &io_control_flags);
	
	if (!gpio_is_valid(spk_power)) {
		dev_err(&pdev->dev, "invalid gpio%d\n", spk_power);
		//goto out;
	} else {
		err  = devm_gpio_request(&pdev->dev, spk_power, "spk_power");
		if (err) {
			dev_err(&pdev->dev,
				"failed to request GPIO%d for usb host0\n", spk_power);
			ret = err;
			goto out;
		}
		gpio_direction_output(spk_power, OUTPUT_HIGH);
		DBG_IO("xxxx spk_power:%d\n", gpio_get_value(spk_power));
	}		

	working_led = of_get_named_gpio_flags(of_node, "working_led", 0, &io_control_flags);
	
	if (!gpio_is_valid(working_led)) {
		dev_err(&pdev->dev, "invalid gpio%d\n", working_led);
		//goto out;
	} else {
		err  = devm_gpio_request(&pdev->dev, working_led, "working_led");
		if (err) {
			dev_err(&pdev->dev,
				"failed to request GPIO%d for working_led\n", working_led);
			ret = err;
			goto out;
		}
		gpio_direction_output(working_led, OUTPUT_HIGH);
		DBG_IO("xxxx working_led:%d\n", gpio_get_value(working_led));
	}	
	
	led_power = of_get_named_gpio_flags(of_node, "led_power", 0, &io_control_flags);
	
	if (!gpio_is_valid(led_power)) {
		dev_err(&pdev->dev, "invalid gpio%d\n", led_power);
		//goto out;
	} else {
		err  = devm_gpio_request(&pdev->dev, led_power, "led_power");
		if (err) {
			dev_err(&pdev->dev,
				"failed to request GPIO%d for led_power\n", led_power);
			ret = err;
			goto out;
		}
		gpio_direction_output(led_power, OUTPUT_HIGH);
		DBG_IO("xxxx led_power:%d\n", gpio_get_value(led_power));
	}		

	pwm_led1 = of_get_named_gpio_flags(of_node, "pwm_led1", 0, &io_control_flags);
	
	if (!gpio_is_valid(pwm_led1)) {
		dev_err(&pdev->dev, "invalid gpio%d\n", pwm_led1);
		//goto out;
	} else {
		err  = devm_gpio_request(&pdev->dev, pwm_led1, "pwm_led1");
		if (err) {
			dev_err(&pdev->dev,
				"failed to request GPIO%d for pwm_led1\n", pwm_led1);
			ret = err;
			goto out;
		}
		gpio_direction_output(pwm_led1, OUTPUT_HIGH);
		DBG_IO("xxxx pwm_led1:%d\n", gpio_get_value(pwm_led1));
	}		

	pwm_led2 = of_get_named_gpio_flags(of_node, "pwm_led2", 0, &io_control_flags);
	
	if (!gpio_is_valid(pwm_led2)) {
		dev_err(&pdev->dev, "invalid gpio%d\n", pwm_led2);
		//goto out;
	} else {
		err  = devm_gpio_request(&pdev->dev, pwm_led2, "pwm_led2");
		if (err) {
			dev_err(&pdev->dev,
				"failed to request GPIO%d for pwm_led2\n", pwm_led2);
			ret = err;
			goto out;
		}
		gpio_direction_output(pwm_led2, OUTPUT_LOW);
		DBG_IO("xxxx pwm_led2:%d\n", gpio_get_value(pwm_led2));
	}		

	doorbell = of_get_named_gpio_flags(of_node, "doorbell", 0, &io_control_flags);
	
	if (!gpio_is_valid(doorbell)) {
		dev_err(&pdev->dev, "invalid gpio%d\n", doorbell);
		//goto out;
	} else {
		err  = devm_gpio_request(&pdev->dev, doorbell, "doorbell");
		if (err) {
			dev_err(&pdev->dev,
				"failed to request GPIO%d for doorbell\n", doorbell);
			ret = err;
			goto out;
		}
		gpio_direction_output(doorbell, OUTPUT_HIGH);
		//gpio_direction_input(doorbell);
		DBG_IO("xxxx doorbell:%d\n", gpio_get_value(doorbell));
	}		

	open_door = of_get_named_gpio_flags(of_node, "open_door", 0, &io_control_flags);
	
	if (!gpio_is_valid(open_door)) {
		dev_err(&pdev->dev, "invalid gpio%d\n", open_door);
		//goto out;
	} else {
		err  = devm_gpio_request(&pdev->dev, open_door, "open_door");
		if (err) {
			dev_err(&pdev->dev,
				"failed to request GPIO%d for open_door\n", open_door);
			ret = err;
			goto out;
		}
		//gpio_direction_input(open_door, OUTPUT_HIGH);
		gpio_direction_input(open_door);
		DBG_IO("xxxx open_door:%d\n", gpio_get_value(open_door));
	}			

	fire_alm = of_get_named_gpio_flags(of_node, "fire_alm", 0, &io_control_flags);
	
	if (!gpio_is_valid(fire_alm)) {
		dev_err(&pdev->dev, "invalid gpio%d\n", fire_alm);
		//goto out;
	} else {
		err  = devm_gpio_request(&pdev->dev, fire_alm, "fire_alm");
		if (err) {
			dev_err(&pdev->dev,
				"failed to request GPIO%d for fire_alm\n", fire_alm);
			ret = err;
			goto out;
		}
		//gpio_direction_output(fire_alm, OUTPUT_HIGH);
		gpio_direction_input(fire_alm);
		DBG_IO("xxxx fire_alm:%d\n", gpio_get_value(fire_alm));
	}		

	ds = of_get_named_gpio_flags(of_node, "ds", 0, &io_control_flags);
	
	if (!gpio_is_valid(ds)) {
		dev_err(&pdev->dev, "invalid gpio%d\n", ds);
		//goto out;
	} else {
		err  = devm_gpio_request(&pdev->dev, ds, "ds");
		if (err) {
			dev_err(&pdev->dev,
				"failed to request GPIO%d for ds\n", ds);
			ret = err;
			goto out;
		}
		//gpio_direction_output(ds, OUTPUT_HIGH);
		gpio_direction_input(ds);
		DBG_IO("xxxx ds:%d\n", gpio_get_value(ds));
	}	

	green_led = of_get_named_gpio_flags(of_node, "green_led", 0, &io_control_flags);
	
	if (!gpio_is_valid(green_led)) {
		dev_err(&pdev->dev, "invalid gpio%d\n", green_led);
		//goto out;
	} else {
		err  = devm_gpio_request(&pdev->dev, green_led, "green_led");
		if (err) {
			dev_err(&pdev->dev,
				"failed to request GPIO%d for green_led\n", green_led);
			ret = err;
			goto out;
		}
		gpio_direction_output(green_led, OUTPUT_HIGH);
		DBG_IO("xxxx green_led:%d\n", gpio_get_value(green_led));
	}		

	red_led = of_get_named_gpio_flags(of_node, "red_led", 0, &io_control_flags);
	
	if (!gpio_is_valid(red_led)) {
		dev_err(&pdev->dev, "invalid gpio%d\n", red_led);
		//goto out;
	} else {
		err  = devm_gpio_request(&pdev->dev, red_led, "red_led");
		if (err) {
			dev_err(&pdev->dev,
				"failed to request GPIO%d for red_led\n", red_led);
			ret = err;
			goto out;
		}
		gpio_direction_output(red_led, OUTPUT_LOW);
		DBG_IO("xxxx red_led:%d\n", gpio_get_value(red_led));
	}	

	relay_en = of_get_named_gpio_flags(of_node, "relay_en", 0, &io_control_flags);
	
	if (!gpio_is_valid(relay_en)) {
		dev_err(&pdev->dev, "invalid gpio%d\n", relay_en);
		//goto out;
	} else {
		err  = devm_gpio_request(&pdev->dev, relay_en, "relay_en");
		if (err) {
			dev_err(&pdev->dev,
				"failed to request GPIO%d for relay_en\n", relay_en);
			ret = err;
			goto out;
		}
		gpio_direction_output(relay_en, OUTPUT_LOW);
		DBG_IO("xxxx relay_en:%d\n", gpio_get_value(relay_en));
	}		
	r485_en = of_get_named_gpio_flags(of_node, "r485_en", 0, &io_control_flags);
	
		DBG_IO("1xxxx r485_en:%d\n", gpio_get_value(r485_en));
	if (!gpio_is_valid(r485_en)) {
		dev_err(&pdev->dev, "invalid gpio%d\n", r485_en);
		//goto out;
	} else {
		err  = devm_gpio_request(&pdev->dev, r485_en, "r485_en");
		if (err) {
			dev_err(&pdev->dev,
				"failed to request GPIO%d for r485_en\n", r485_en);
			ret = err;
			goto out;
		}
		DBG_IO("2xxxx r485_en:%d\n", gpio_get_value(r485_en));
		gpio_direction_output(r485_en, OUTPUT_HIGH);
		DBG_IO("3xxxx r485_en:%d\n", gpio_get_value(r485_en));
	}	
	
	n4g_en = of_get_named_gpio_flags(of_node, "n4g_en", 0, &io_control_flags);
	
		DBG_IO("1xxxx n4g_en:%d\n", gpio_get_value(n4g_en));
	if (!gpio_is_valid(n4g_en)) {
		dev_err(&pdev->dev, "invalid gpio%d\n", n4g_en);
		//goto out;
	} else {
		err  = devm_gpio_request(&pdev->dev, n4g_en, "n4g_en");
		if (err) {
			dev_err(&pdev->dev,
				"failed to request GPIO%d for n4g_en\n", n4g_en);
			ret = err;
			goto out;
		}
		DBG_IO("2xxxx n4g_en:%d\n", gpio_get_value(n4g_en));
		gpio_direction_output(n4g_en, OUTPUT_HIGH);
		DBG_IO("3xxxx n4g_en:%d\n", gpio_get_value(n4g_en));
	}	
	
	bl_en = of_get_named_gpio_flags(of_node, "bl_en", 0, &io_control_flags);
	
		DBG_IO("1xxxx bl_en:%d\n", gpio_get_value(bl_en));
	if (!gpio_is_valid(bl_en)) {
		dev_err(&pdev->dev, "invalid gpio%d\n", bl_en);
		//goto out;
	} else {
		err  = devm_gpio_request(&pdev->dev, bl_en, "bl_en");
		if (err) {
			dev_err(&pdev->dev,
				"failed to request GPIO%d for bl_en\n", bl_en);
			ret = err;
			goto out;
		}
		DBG_IO("2xxxx bl_en:%d\n", gpio_get_value(bl_en));
		gpio_direction_output(bl_en, OUTPUT_HIGH);
		DBG_IO("3xxxx bl_en:%d\n", gpio_get_value(bl_en));
	}	
	
	usb_en = of_get_named_gpio_flags(of_node, "usb_en", 0, &io_control_flags);
	
		DBG_IO("1xxxx usb_en:%d\n", gpio_get_value(usb_en));
	if (!gpio_is_valid(r485_en)) {
		dev_err(&pdev->dev, "invalid gpio%d\n", usb_en);
		//goto out;
	} else {
		err  = devm_gpio_request(&pdev->dev, usb_en, "usb_en");
		if (err) {
			dev_err(&pdev->dev,
				"failed to request GPIO%d for usb_en\n", usb_en);
			ret = err;
			goto out;
		}
		DBG_IO("2xxxx usb_en:%d\n", gpio_get_value(usb_en));
		gpio_direction_output(usb_en, OUTPUT_HIGH);
		DBG_IO("3xxxx usb_en:%d\n", gpio_get_value(usb_en));
	}		
	
////////////////////////////////////////////////////////////////////////////////////////////////
	for (i = 0; i < ARRAY_SIZE(io_control_attrs); i++) {
		ret = device_create_file(&pdev->dev, &io_control_attrs[i]);
		if (ret) {
			printk("failed to create sysfs file\n");
			break;
		}
	}
 	
out:
	return ret;	
}

static int io_control_remove(struct platform_device *pdev)
{
	int i;
	
	gpio_free(usb_host0);
	gpio_free(wifi_power);
	gpio_free(spk_power);
	gpio_free(working_led);
	gpio_free(led_power);
	gpio_free(pwm_led1);
	gpio_free(pwm_led2);
	gpio_free(doorbell);
	gpio_free(open_door);
	gpio_free(fire_alm);
	gpio_free(ds);
	gpio_free(green_led);
	gpio_free(red_led);
	gpio_free(relay_en);
	gpio_free(r485_en);
	gpio_free(n4g_en);
	gpio_free(bl_en);
	gpio_free(usb_en);
	
	for (i = 0; i < ARRAY_SIZE(io_control_attrs); i++) {
        device_remove_file(&pdev->dev, &io_control_attrs[i]);
	}	
	
	return 0;
}

static const struct of_device_id io_control_match[] = {
	{ .compatible = "goingup,io-control", },
	{},
};
MODULE_DEVICE_TABLE(of, io_control_match);

static struct platform_driver io_control_driver = {
	.probe = io_control_probe,
	.remove = io_control_remove,
	.driver = {
		.name = "io_control",
		.owner = THIS_MODULE,
		.of_match_table = io_control_match,
	},	
};

static int __init io_control_init(void)
{	
	int retval = 0;

	retval = platform_driver_register(&io_control_driver);	
	if (retval < 0) {
		printk(KERN_ERR "%s retval=%d\n", __func__, retval);
		return retval;
	}
	return retval;
}

static void __exit io_control_exit(void)
{
    platform_driver_unregister(&io_control_driver);
}

module_init(io_control_init);
module_exit(io_control_exit);

MODULE_LICENSE("GPL");
